先日、golang の開発リポジトリに generate が入りました。
Go generate: A Proposal
The go build command automates the construction of Go programs but sometimes preliminary processing is required, processing that go build does not support.
https://docs.google.com/document/d/1V03LUfjSADDooDMhe-_K59EgpTEm3V8uvQRuNMAEnjg/edit
皆さんが期待している様な物なのかそうでないのか分かりませんが、ひとまずこの提案書を見る限り
- 使うのはライブラリユーザではなくライブラリ作者
- go build で自動で generate してくれる機能はない
- shell 的なワンライナーは実行出来ない
どちらかと言うと使用するのは開発時で、バイナリを同梱する目的で golang のソースを吐くまでの手順であったり、構造体に特殊なメソッドを生やしたりという目的で使われます。また yacc のソースから golang のソースを吐くなどといった用途も考えられます。生成される物が golang のソースに限られている訳でもありません。
この特殊なメソッドを吐き出す、と聞くとどうしても generics を思い浮かべる方が多いと思いますが、上記の通り「自動では生成されない」という制限がある事から期待されている使い方は現状出来ません。
今日はこの新しく入った generate を使って、どの様な効果が得られるのかを gen
というツールを使って説明したいと思います。
まず以下のコード(food.go
)を用意します。
//go:generate gen -force
package food
// +gen *
type Food struct {
Name string
Price int
}
gen というツールが +gen
となっている部分を扱います。
clipperhouse/gen - GitHub
README.md What’s this? gen is a code-generation tool for Go. It’s intended to offer generics-like fu...
https://github.com/clipperhouse/gen
gen はこの識別が付いている type 宣言から便利な関数群を作ってくれます。
food.go
があるフォルダで以下を実行します。
$ go generate
すると food_gen.go
というコードが生成されます。少し大きすぎるので gist に貼りつけました。詳しくは gen の README を参照して頂きたいですが、配列を扱う上で便利な関数群が生成されます。
あとはこれを使って処理を書くのみとなります。
package main
import (
"fmt"
. "github.com/mattn/go-example/food"
)
func main() {
foods := Foods{
{"リンゴ", 110},
{"みかん", 70},
{"メロン", 400},
}
foods.All(func(f *Food) bool {
if f.Price < 200 {
fmt.Println(f.Name)
}
return true
})
}
この例は gen
を使いましたが、go-assets や go-bindata でバイナリからソースファイルを生成したり、msgp を使って構造体を MessagePack 対応したりといった用途にも使用出来るかと思います。
ライブラリユーザではなくライブラリ開発者にとっては便利な機能だと思いますね。